Skip to content

feat(auth): expose sign.cap + remaining on /auth/config (beta seat counter)#3761

Merged
PierreBrisorgueil merged 2 commits into
masterfrom
feat/auth-config-seat-counter
Jun 1, 2026
Merged

feat(auth): expose sign.cap + remaining on /auth/config (beta seat counter)#3761
PierreBrisorgueil merged 2 commits into
masterfrom
feat/auth-config-seat-counter

Conversation

@PierreBrisorgueil
Copy link
Copy Markdown
Contributor

@PierreBrisorgueil PierreBrisorgueil commented Jun 1, 2026

What

Adds a pure helper modules/auth/services/auth.signupCapacity.js (computeSignupCapacity(rawCap, countFn) → {cap, remaining}) and wires it into the public GET /api/auth/config (getConfig) handler, so the sign block now also returns cap + remaining (seats-left). Enables downstream landing pages to render a "X seats left" private-beta counter.

Why

Upstream-generic half of a downstream private-beta invite gate. The cap enforcement already exists in this controller (signup + OAuth handlers); this only exposes the configured cap + remaining seats to the read-only config endpoint.

Non-breaking / inert by default

When config.sign.cap is null/unset (every current deployment), cap and remaining come back null and UserService.count() is not called (short-circuit). No behavior or perf change for any downstream until it opts in by setting a cap.

Tests

11 unit tests on the helper (null/undefined/numeric/over-cap/cap=0/numeric-string) + controller tests assert the new fields are null on the uncapped path. Lint clean.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Signup capacity information (cap and remaining slots) now included in the /auth/config response.
    • Dynamic computation of available signup capacity based on current user count.
  • Bug Fixes

    • Improved error handling for the configuration endpoint with proper error status codes.
  • Tests

    • Added comprehensive test coverage for signup capacity logic and configuration endpoint behavior.

…dpoint

Adds computeSignupCapacity helper (auth.signupCapacity.js) that is a
no-op when cap is null/undefined/non-numeric (all current deployments),
wiring it into the getConfig handler. count() is never called when
uncapped, keeping the common path identical to before.
Copilot AI review requested due to automatic review settings June 1, 2026 17:03
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 1, 2026

Review Change Stack

Warning

Review limit reached

@PierreBrisorgueil, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 54 minutes and 7 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8df79aad-ea38-416c-845c-c38b0bdbeee1

📥 Commits

Reviewing files that changed from the base of the PR and between 7302eef and 3555217.

📒 Files selected for processing (2)
  • modules/auth/services/auth.signupCapacity.js
  • modules/auth/tests/auth.signupCapacity.unit.tests.js

Walkthrough

This PR adds signup capacity tracking to the authentication config endpoint. A new computeSignupCapacity service computes remaining seats from a configured cap and active user count, then integrates into the public /auth/config response alongside the existing signup fields, while converting the endpoint to async with error handling.

Changes

Signup capacity computation and config integration

Layer / File(s) Summary
Signup capacity service and tests
modules/auth/services/auth.signupCapacity.js, modules/auth/tests/auth.signupCapacity.unit.tests.js
New computeSignupCapacity async function accepts a cap value and async count function, returning {cap: null, remaining: null} for uncapped (missing or non-numeric/non-finite), or {cap, remaining} with remaining floored at zero. Comprehensive test suite covers uncapped inputs, capped calculations, numeric string coercion, over-cap flooring, and cap = 0 edge case.
Config endpoint capacity integration
modules/auth/controllers/auth.controller.js, modules/auth/tests/auth.config.controller.unit.tests.js
getConfig import adds computeSignupCapacity, converts endpoint to async, computes and includes sign.cap and sign.remaining via the service with try/catch error handling (422 on failure). All controller tests updated to await the async endpoint; unauthenticated test adds assertions that uncapped config returns null capacity fields.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • pierreb-devkit/Node#3210: Both PRs modify the auth getConfig implementation for the public /api/auth/config endpoint—PR #3210 adds the endpoint and returns sign.in/sign.up, while the main PR extends getConfig to compute and include sign.cap and sign.remaining via computeSignupCapacity.

Suggested labels

Feat

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding exposure of sign.cap and remaining fields to the /auth/config endpoint for a beta seat counter feature.
Description check ✅ Passed The description covers most required sections but is missing the structured template format with formal sections for Scope, Validation checklist, and Guardrails check details.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/auth-config-seat-counter

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov Bot commented Jun 1, 2026

Codecov Report

❌ Patch coverage is 94.44444% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 90.14%. Comparing base (0a9db27) to head (3555217).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #3761      +/-   ##
==========================================
- Coverage   90.14%   90.14%   -0.01%     
==========================================
  Files         150      151       +1     
  Lines        4961     4970       +9     
  Branches     1574     1577       +3     
==========================================
+ Hits         4472     4480       +8     
- Misses        384      385       +1     
  Partials      105      105              
Flag Coverage Δ
integration 59.43% <77.77%> (-0.01%) ⬇️
unit 68.91% <94.44%> (+0.03%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 6ab44fd...3555217. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a small auth “signup capacity” helper and exposes sign.cap + sign.remaining on the public GET /api/auth/config endpoint to support private-beta “seats left” UI.

Changes:

  • Introduces computeSignupCapacity(rawCap, countFn) to compute { cap, remaining } with an uncapped short-circuit.
  • Updates AuthController.getConfig to return sign.cap and sign.remaining.
  • Adds unit tests for the helper and extends existing controller unit tests to assert null capacity fields in the uncapped path.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
modules/auth/services/auth.signupCapacity.js New helper to compute cap + remaining (may call account-count).
modules/auth/controllers/auth.controller.js getConfig now includes sign.cap + sign.remaining and awaits capacity computation.
modules/auth/tests/auth.signupCapacity.unit.tests.js New unit tests for the helper.
modules/auth/tests/auth.config.controller.unit.tests.js Updates controller tests to await and assert cap/remaining are null when uncapped.

Comment thread modules/auth/services/auth.signupCapacity.js
Comment thread modules/auth/tests/auth.signupCapacity.unit.tests.js Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@modules/auth/controllers/auth.controller.js`:
- Around line 607-649: The unauthenticated getConfig handler calls
computeSignupCapacity which invokes UserService.count on every request when
config.sign.cap is set — add a short-TTL cache to avoid per-request collection
counts: inside getConfig (or a small helper) wrap calls to
computeSignupCapacity/UserService.count with an in-memory cache keyed e.g.
"signup_capacity" that returns the last computed {cap, remaining} for a
configurable TTL (e.g. 30–120s), use the cached value when not expired and only
call computeSignupCapacity/UserService.count when expired, and ensure the cache
key is invalidated/updated on user creation/seat changes if you already have
hooks to do so.

In `@modules/auth/services/auth.signupCapacity.js`:
- Around line 10-11: The current coercion treats blank/whitespace rawCap as 0
because Number('') === 0; update the guard around rawCap/cap so blank strings
are treated as "uncapped" (null) instead of 0. Specifically, in the logic that
computes cap from rawCap (referencing rawCap and cap and the
Number()/Number.isFinite() check), add a check that if typeof rawCap ===
'string' and rawCap.trim() === '' then treat it as null, and only call
Number(rawCap) and proceed to the Number.isFinite(cap) test for non-blank inputs
so blank/whitespace config values do not produce cap: 0 or trigger countFn().

In `@modules/auth/tests/auth.signupCapacity.unit.tests.js`:
- Around line 27-31: Add a unit test in
modules/auth/tests/auth.signupCapacity.unit.tests.js that asserts
computeSignupCapacity treats empty or whitespace-only cap strings as uncapped
(like the existing 'non-numeric cap → treated as uncapped' test); call
computeSignupCapacity with '' and with a whitespace string (e.g. '   '), expect
resolves.toEqual({ cap: null, remaining: null }), and verify the provided
countFn is not called—this pins the intended guard behavior in the
computeSignupCapacity helper.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1db2dbc1-846a-43bb-b9ba-3f132c9d0a36

📥 Commits

Reviewing files that changed from the base of the PR and between 6ab44fd and 7302eef.

📒 Files selected for processing (4)
  • modules/auth/controllers/auth.controller.js
  • modules/auth/services/auth.signupCapacity.js
  • modules/auth/tests/auth.config.controller.unit.tests.js
  • modules/auth/tests/auth.signupCapacity.unit.tests.js

Comment thread modules/auth/controllers/auth.controller.js
Comment thread modules/auth/services/auth.signupCapacity.js Outdated
Comment thread modules/auth/tests/auth.signupCapacity.unit.tests.js
…apacity

- Blank/whitespace rawCap (e.g. SIGN_CAP="") now treated as uncapped (null)
  instead of coercing to 0 via Number('')
- cap ≤ 0 short-circuits countFn (remaining is deterministically 0, no DB hit)
- Add unit tests: empty string cap, whitespace cap, cap=0 no-count assertion
@PierreBrisorgueil PierreBrisorgueil merged commit 7ed5291 into master Jun 1, 2026
8 checks passed
@PierreBrisorgueil PierreBrisorgueil deleted the feat/auth-config-seat-counter branch June 1, 2026 17:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants